package cn.diancan.dao.impl;


import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import javax.persistence.Id; 

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.jdbc.ReturningWork;
import org.springframework.stereotype.Component;

import cn.diancan.dao.MyBaseDao;
  

@Component("MyBaseDao")
public class MyBaseDaoImpl<T> implements MyBaseDao<T> {

	private SessionFactory sessionFactory;

	
	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	@Resource(name="sessionFactory")
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	protected Session getCurrentSession() {
	    
	    return sessionFactory.getCurrentSession();
	}

	public Serializable save(T o)  {
		return this.getCurrentSession().save(o);
	} 

	public void delete(T o) { 
	    	this.getCurrentSession().delete(o);
	}

	public void update(T o) {
		try {
			this.getCurrentSession().update(o);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void saveOrUpdate(T o) {
		this.getCurrentSession().saveOrUpdate(o);
	}
	
	
	@Override
	public void saveUseUtf8Mb4(T o) {
	    this.getUtf8Mb4Session().save(o); 
	}
	@Override
	public void saveOrUpdateUseUtf8Mb4(T o) { 
	    this.getUtf8Mb4Session().saveOrUpdate(o); 
	}
	@Override
	public void updateUtf8Mb4(T o) { 
	    this.getUtf8Mb4Session().update(o);
	}

	
	private Session getUtf8Mb4Session(){
	    Session s =  this.getCurrentSession();
	    s.doReturningWork(new ReturningWork<Object>() {
		@Override
		public Object execute(java.sql.Connection conn)throws SQLException {  
		    	try {
			    java.sql.Statement stmt = conn.createStatement();
			    stmt.executeQuery("SET NAMES 'utf8mb4'");
			} catch (Exception e) { 
			    e.printStackTrace();
			} 
		        return null;  
		} 
	    }); 
	    return s;
	} 
	

	public List<T> find(String hql) {
		return this.getCurrentSession().createQuery(hql).list();
	}
	
//	public List findBySql(String hql) {
//		return this.getCurrentSession().createSQLQuery(hql).addScalar("ID").addScalar("GOODS_ID").addScalar("REPERTORY_ID").list();
//	}
	public List<Object[]> findBySql(String hql) {
		List<Object[]> list = this.getCurrentSession().createSQLQuery(hql).list();
		return list;
//		this.getCurrentSession().createSQLQuery(hql).addScalar("ID").addScalar("GOODS_ID").addScalar("REPERTORY_ID").list();
	}
	
	public List findList(String hql){
		return this.getCurrentSession().createQuery(hql).list();
	}
	public List<T> find(String hql, Object[] param) {
		Query q = this.getCurrentSession().createQuery(hql);
		if (param != null && param.length > 0) {
			for (int i = 0; i < param.length; i++) {
				q.setParameter(i, param[i]);
			}
		}
		return q.list();
	}

	public List<T> find(String hql, List<Object> param) {
		Query q = this.getCurrentSession().createQuery(hql);
		if (param != null && param.size() > 0) {
			for (int i = 0; i < param.size(); i++) {
				q.setParameter(i, param.get(i));
			}
		}
		return q.list();
	}

	public List<T> find(String hql, Object[] param, Integer page, Integer rows) {
		try {
			if (page == null || page < 1) {
				page = 1;
			}
			if (rows == null || rows < 1) {
				rows = 10;
			}
			Query q = this.getCurrentSession().createQuery(hql);
			if (param != null && param.length > 0) {
				for (int i = 0; i < param.length; i++) {
					q.setParameter(i, param[i]);
				}
			}
			return q.setFirstResult((page - 1) * rows).setMaxResults(rows).list();
		} catch (Exception e) { 
			e.printStackTrace();
		}
		return null;
	}

	public List<T> find(String hql, List<Object> param, Integer page, Integer rows) {
		if (page == null || page < 1) {
			page = 1;
		}
		if (rows == null || rows < 1) {
			rows = 10;
		}
		Query q = this.getCurrentSession().createQuery(hql);
		if (param != null && param.size() > 0) {
			for (int i = 0; i < param.size(); i++) {
				q.setParameter(i, param.get(i));
			}
		}
		return q.setFirstResult((page - 1) * rows).setMaxResults(rows).list();
	}
	
	public List<Object[]> findSql(String hql,Object[] param, Integer page, Integer rows) {
		if (page == null || page < 1) {
			page = 1;
		}
		if (rows == null || rows < 1) {
			rows = 10;
		}
		Query q = this.getCurrentSession().createSQLQuery(hql);
		if (param != null && param.length > 0) {
			for (int i = 0; i < param.length; i++) {
				q.setParameter(i, param[i]);
			}
		}
		return q.setFirstResult((page - 1) * rows).setMaxResults(rows).list();
	}
	
	public List<Object[]> findSql(String hql, List<Object> param, Integer page, Integer rows) {
		if (page == null || page < 1) {
			page = 1;
		}
		if (rows == null || rows < 1) {
			rows = 10;
		}
		Query q = this.getCurrentSession().createSQLQuery(hql);
		if (param != null && param.size() > 0) {
			for (int i = 0; i < param.size(); i++) {
				q.setParameter(i, param.get(i));
			}
		}
		return q.setFirstResult((page - 1) * rows).setMaxResults(rows).list();
	}
	

	public List<T> find(String hql,  Integer page, Integer rows) {
		if (page == null || page < 1) {
			page = 1;
		}
		if (rows == null || rows < 1) {
			rows = 10;
		}
		Query q = this.getCurrentSession().createQuery(hql);
		
		return q.setFirstResult((page - 1) * rows).setMaxResults(rows).list();
	}

	public T get(Class<T> c, Serializable id) {
		return (T) this.getCurrentSession().get(c, id);
	}

	public T get(String hql, Object[] param) {
		List<T> l = this.find(hql, param,1,1);//取第一页第一条
		if (l != null && l.size() > 0) {
			return l.get(0);
		} else {
			return null;
		}
	}

	public T get(String hql, List<Object> param) {
		List<T> l = this.find(hql, param,1,1);//取第一页第一条
		if (l != null && l.size() > 0) {
			return l.get(0);
		} else {
			return null;
		}
	}

	public Long count(String hql) {
		return (Long) this.getCurrentSession().createQuery(hql).uniqueResult();
	}
	public Integer count2(String hql) {
		return (Integer )this.getCurrentSession().createQuery(hql).uniqueResult();
	}
	public Double count1(String hql) {
		return (Double) this.getCurrentSession().createQuery(hql).uniqueResult();
	}
	public Object count3(String hql) {
		return this.getCurrentSession().createQuery(hql).uniqueResult();
	}
	public Object count3(String hql, Object[] param) {
		Query q = this.getCurrentSession().createQuery(hql);
		if (param != null && param.length > 0) {
			for (int i = 0; i < param.length; i++) {
				q.setParameter(i, param[i]);
			}
		}
		return  q.uniqueResult();
	}

	public Long count(String hql, Object[] param) {
		Query q = this.getCurrentSession().createQuery(hql);
		if (param != null && param.length > 0) {
			for (int i = 0; i < param.length; i++) {
				q.setParameter(i, param[i]);
			}
		}
		return (Long) q.uniqueResult();
	}

	public Object countSQL(String hql,Object[] param) {
		Query q = this.getCurrentSession().createSQLQuery(hql);
		if (param != null && param.length > 0) {
			for (int i = 0; i < param.length; i++) {
				q.setParameter(i, param[i]);
			}
		}
		return  q.uniqueResult();
	}
	public Object countSQL3(String hql, List<Object> param) {
		Query q = this.getCurrentSession().createSQLQuery(hql);
		if (param != null && param.size() > 0) {
			for (int i = 0; i < param.size(); i++) {
				q.setParameter(i, param.get(i));
			}
		}
		return  q.uniqueResult();
	}
	public BigDecimal countSQL2(String hql) {
		Query q = this.getCurrentSession().createSQLQuery(hql);
//		if (param != null && param.length > 0) {
//			for (int i = 0; i < param.length; i++) {
//				q.setParameter(i, param[i]);
//			}
//		}
		return  (BigDecimal) q.uniqueResult();
	}
	public Double countSQL1(String hql) {
		Query q = this.getCurrentSession().createSQLQuery(hql);
//		if (param != null && param.length > 0) {
//			for (int i = 0; i < param.length; i++) {
//				q.setParameter(i, param[i]);
//			}
//		}
		return (Double) q.uniqueResult();
	}
	public Long count(String hql, List<Object> param) {
		Query q = this.getCurrentSession().createQuery(hql);
		if (param != null && param.size() > 0) {
			for (int i = 0; i < param.size(); i++) {
				q.setParameter(i, param.get(i));
			}
		}
		return (Long) q.uniqueResult();
	}
	
	public Double countToDouble(String hql, List<Object> param) {
		Query q = this.getCurrentSession().createQuery(hql);
		if (param != null && param.size() > 0) {
			for (int i = 0; i < param.size(); i++) {
				q.setParameter(i, param.get(i));
			}
		}
		return (Double) q.uniqueResult();
	}

	public Integer executeHql(String hql) {
		return this.getCurrentSession().createQuery(hql).executeUpdate();
	}

	public Integer executeHql(String hql, Object[] param) {
		Query q = this.getCurrentSession().createQuery(hql);
		if (param != null && param.length > 0) {
			for (int i = 0; i < param.length; i++) {
				q.setParameter(i, param[i]);
			}
		}
		return q.executeUpdate();
	}

	public Integer executeHql(String hql, List<Object> param) {
		Query q = this.getCurrentSession().createQuery(hql);
		if (param != null && param.size() > 0) {
			for (int i = 0; i < param.size(); i++) {
				q.setParameter(i, param.get(i));
			}
		}
		return q.executeUpdate();
	}

	@Override
	public String find2(String hql) {
		 Query q =this.getCurrentSession().createQuery(hql);
		q.setFirstResult(0);
		q.setMaxResults(1);
		return (String)q.uniqueResult();
		
		//return (String)this.getCurrentSession().createQuery(hql).uniqueResult();
	}
	
	@Override
	public Integer executeSQLHql(String hql, List<Object> param) {
		Query q = this.getCurrentSession().createSQLQuery(hql);
		if (param != null && param.size() > 0) {
			for (int i = 0; i < param.size(); i++) {
				q.setParameter(i, param.get(i));
			}
		}
		return q.executeUpdate();
	}

	@Override
	public <T> int updateIsNotNull(T model) {
		Class clazz = model.getClass();
		String hql="UPDATE "+ clazz.getName() +" SET ";
		List<Object> param = new ArrayList<Object>();
		try {
			BeanInfo binfo= Introspector.getBeanInfo(clazz,Object.class);
			PropertyDescriptor[] propertys= binfo.getPropertyDescriptors();
			String idStr="";
			Object idValue=null;
			for (PropertyDescriptor property : propertys) {
				Method mread= property.getReadMethod();
				Id id= mread.getAnnotation(Id.class);
				if(null ==id && null !=mread.invoke(model, null) ){
					hql +=" "+property.getName()+"=?,";
					param.add(mread.invoke(model, null));
					continue;
				}
				
				if(null!=id  ){
					idStr= " Where "+property.getName()+"=?";
					idValue=mread.invoke(model, null);
				}
				
			}
			hql = hql.substring(0, hql.length()-1);
			hql+=idStr;
			param.add(idValue);
			
			executeHql(hql,param);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return 0;
	}

	@Override
	public Integer executeSQLHql(String hql, Object[] param) {
		Query q = this.getCurrentSession().createSQLQuery(hql);
		if (param != null && param.length > 0) {
			for (int i = 0; i < param.length ; i++) {
				q.setParameter(i, param[i]);
			}
		}
		return q.executeUpdate();
	}

	@Override
	public Integer executeHqlUseUtf8Mb4(String hql, Object[] param) {
		try { 
		    Query q = this.getUtf8Mb4Session().createQuery(hql);
			if (param != null && param.length > 0) {
				for (int i = 0; i < param.length; i++) {
					q.setParameter(i, param[i]);
				}
			}
			return q.executeUpdate();
		} catch (HibernateException e) { 
		    e.printStackTrace();
		}
		return 0;
	}
	
	


}
